package com.only4play.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.only4play.common.constants.ErrorCodeEnum;
import com.only4play.common.exception.ApplicationException;
import com.only4play.common.utils.FilesUtils;
import com.only4play.config.AssetResourceConfigProperties;
import com.only4play.dto.AssetResourceUploadDto;
import com.only4play.idgenerator.service.SingIdGenerator;
import com.only4play.mapper.AssetResourceMapper;
import com.only4play.model.entity.AssetResourceEntity;
import com.only4play.service.AssetResourceService;
import com.only4play.vo.AssetResourceDownloadVo;
import org.apache.tomcat.util.http.fileupload.disk.DiskFileItem;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;

/**
 * @author liyuncong
 * @version 1.0
 * @file AssetResourceServiceImpl
 * @brief AssetResourceServiceImpl
 * @details AssetResourceServiceImpl
 * @date 2023-12-22
 *
 * Edit History
 * ----------------------------------------------------------------------------
 * DATE                     NAME               DESCRIPTION
 * 2023-12-22               liyuncong          Created
 */

@Service
public class AssetResourceServiceImpl extends ServiceImpl<AssetResourceMapper, AssetResourceEntity>
    implements AssetResourceService {

    @Autowired
    private AssetResourceConfigProperties properties;

    @Autowired
    private SingIdGenerator idGenerator;

    @Override
    public String upload(AssetResourceUploadDto uploadDto) {
        if (Objects.isNull(uploadDto)) {
            throw new ApplicationException(ErrorCodeEnum.VALIDATE_ERROR);
        }
        MultipartFile resource = uploadDto.getResource();
        String resourceName = resource.getOriginalFilename();
        if (!checkSize(resource)) {
            throw new ApplicationException(ErrorCodeEnum.VALIDATE_ERROR);
        }
        Path relativePath = getRelativePath(resourceName);
        Path absolutePath = getAbsolutePath(relativePath);
        if (!FilesUtils.checkPath(absolutePath, false)) {
            throw new ApplicationException(ErrorCodeEnum.VALIDATE_ERROR);
        }
        try {
            Files.copy(resource.getInputStream(), absolutePath);
        } catch (IOException exception) {
            throw new ApplicationException(ErrorCodeEnum.SERVER_ERROR);
        }
        String checksum = FilesUtils.getChecksum(absolutePath);
        Long resourceId = idGenerator.snowFlake();
        AssetResourceEntity entity = AssetResourceEntity.builder()
            .resourceId(resourceId)
            .resourceName(resourceName)
            .resourceStoragePath(relativePath.toString())
            .mimeType(resource.getContentType())
            .ownerType(uploadDto.getOwnerType())
            .ownerId(uploadDto.getOwnerId())
            .checksum(checksum)
            .build();
        boolean flag = this.save(entity);
        if (flag) {
            return String.valueOf(resourceId);
        }
        return "";
    }

    @Override
    public AssetResourceDownloadVo download(Long resourceId) {
        AssetResourceEntity resource = this.getById(resourceId);
        if (Objects.nonNull(resource)) {
            Path absolutePath = getAbsolutePath(Paths.get(resource.getResourceStoragePath()));
            if (Files.exists(absolutePath)) {
                return AssetResourceDownloadVo.builder()
                    .resourceId(resource.getResourceId())
                    .resourceName(resource.getResourceName())
                    .mimeType(resource.getMimeType())
                    .resource(absolutePath.toFile())
                    .ownerId(resource.getOwnerId())
                    .ownerType(resource.getOwnerType())
                    .build();
            }
        }
        return null;
    }

    protected boolean checkSize(MultipartFile file) {
        if (Objects.isNull(file)) {
            return false;
        }
        return properties.getDefaultLimitSize() >= file.getSize();
    }

    protected String getFilename() {
        return UUID.randomUUID().toString().replaceAll("-", "");
    }

    protected Path getAbsolutePath(Path relativePath) {
        if (Objects.isNull(relativePath)) {
            return getRelativePath("");
        }
        return Paths.get(properties.getStorageRoot(), relativePath.toString());
    }

    protected Path getRelativePath(String filename) {
        return Paths.get(joinPathByStoreRule(filename), getFilename());
    }

    private String joinPathByStoreRule(String filename) {
        final String AUTO_BY_TIME = "auto_by_time_";
        final String AUTO_BY_NAME = "auto_by_name_";
        final long LEVEL_ONE_AMOUNT = 100L;
        //目前创建文件夹规则就一种，根据日期创建
        if (properties.getStorageRule().equalsIgnoreCase("time")) {
            return AUTO_BY_TIME + LocalDate.now();
        }
        if (properties.getStorageRoot().equalsIgnoreCase("name")) {
            long hashCode = filename.hashCode();
            long parent = hashCode % LEVEL_ONE_AMOUNT;
            long child = hashCode / LEVEL_ONE_AMOUNT % (LEVEL_ONE_AMOUNT * LEVEL_ONE_AMOUNT);
            return AUTO_BY_NAME + parent + "/" + child;
        }
        return AUTO_BY_TIME + LocalDate.now();
    }
}
